#ifndef GLOBAL_H
#define GLOBAL_H

#include <qglobal.h>




//修改!!!
#define _Format sprintf
#define _T QObject::tr
//#define _T QCoreApplication::tr

//#define CONFIG(X) config.configHash[#X].toInt()



/////////////////通用函数///////////////////////


//n1~n2(不包括n2)随机数,n1和n2大小可以互换
long Random(long n1, long n2);

//随机数命中率(m分之n)
long RandTarget(int n, int m = 10000);

//n1到n2,取n个不同的数到arr,elementSize为元素大小
//使用hash
bool GetDifferentNumber(long n1, long n2, void* arr,int n,int elementSize);


#include <QTextCodec>
//非ASCII码的个数
int nonASCIICount(QString str);


/////////////////Qt函数

//拷贝目录
bool copyDirectoryFiles(const QString &fromDir, const QString &toDir, bool coverFileIfExist);

#include <QFile>
//从assets拷贝文件和设置权限(安卓用),不覆盖
bool copyFileAndSetPermissions(const QString& filename, QFileDevice::Permissions permissionSpec);


//自定义 控制台输出
void customMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);



//class QPixmap;
//半透明显示图片
QPixmap Ltrans(QPixmap &pix1, int Alpha =255);

//显示一段内存(可用QByteArray代替!!)
void showHex(char *data,unsigned long length);


#include <QDebug>
#include <QDateTime>

inline void Warning(QString str)
{
    qWarning() << str;
}
inline void Debug(QString str)
{
    qDebug() << str;
}
inline void Critical(QString str)
{
    qCritical() << str;
}
inline void ShowTime()
{
    qDebug() << QDateTime::currentDateTime().time();
}



//////////////等待函数(不阻塞事件处理)//////////////////////

void Wait(int msec);

/*
    Wait1 和 Wait2 会让CPU飙升,且点了关闭按钮,也无法退出循环(除非到时)
*/
void Wait1(int msec);
void Wait2(int msec);






//
//Q_DECLARE_TR_FUNCTIONS(GameSlot)

//QTextCodec::setCodecForTr(QTextCodec::codecForName("System"));  //消除乱码






////////////////////事件过滤器///////////////////

#include <QObject>
#include <QEvent>

/*
 * 用法:
 * new EventFilter(要过滤的对象(可以为nullptr),parent);
 * 改写eventFilter函数,过滤watched的事件
*/

class EventFilter : public QObject
{
    Q_OBJECT
public:
    explicit EventFilter(QObject *watched = nullptr, QObject *parent = nullptr) :
           QObject(parent),
           m_watched(watched)
    {
    }
    virtual ~EventFilter(){}

    bool eventFilter(QObject *watched, QEvent *event)
    {
           if (m_watched == nullptr ||
                   watched == m_watched
              )
           {
                   if (event->type() == QEvent::MouseButtonDblClick)
                   {
                            qDebug() << "EventFilter";
                            return true;
                   }
           }
       return false;
    }

private:
    QObject *m_watched;
};





//////////////////配置文件////////////////////


#include <QHash>
#include <QFile>
#include <QDebug>
#include <QByteArray>

class Config
{
public:
    Config(QString strFileName = "Config.cfg")
    {
        configFile.setFileName(strFileName);
        //readConfigFile();
    }
    int readConfigFile(QVariantMap &mapConfig)
    {
        if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text))
        {
            qCritical() << "Open file failed.";
            return -1;
        }
        else
        {
            while (!configFile.atEnd())
            {
                QString str;
                int n;

                str = QString::fromLatin1(configFile.readLine());

                if(str.indexOf("#") == 0)
                    continue;
                if((n = str.indexOf("=")) == -1)
                    continue;

                //qDebug() << n << str.left(n).trimmed() << "====" << str.mid(n+1).trimmed();
                mapConfig[str.left(n).trimmed()] = str.mid(n+1).trimmed();
                //qDebug()<<configHash[str.left(n).trimmed()];
            }
            configFile.close();
        }
        return 0;
    }

public:
    QFile configFile;
};



////////////////////随机数///////////////////
inline int lmsSrand(int type)
{
    static int s = QDateTime::currentDateTime().time().msec();
    switch (type) {
    case -1:    //每次都随机
        type = QDateTime::currentDateTime().time().msec();
        break;
    case 0:     //固定一个随机种子(可以调试)
        type = s;
        break;
    default:    //(具体随机种子)
        //type = config.configHash["RAND"].toInt();
        break;
    }
    ::qsrand(type);
    return type;
    //qDebug()<<config.configHash["RAND"].toInt();
}









////////////////////生产者模式类///////////////////

#include <QSemaphore>
#include <QQueue>
#include <QMutex>

//游戏数据基类,要在游戏中再次继承,生产消费者模型中使用!
struct __ProducerData
{
    explicit __ProducerData();
    virtual ~__ProducerData();

public:
    int type;       //数据类型
    void *sender;   //发送者,某个客户(_ClientInfo)

public:
    virtual void Release();
};

//生产者/消费者模型
class ProducerModel
{
public:
    explicit ProducerModel();
    virtual ~ProducerModel();

public:

    void init()
    {
        //释放信号量
        int t = available();
        if(t > 0)
            usingNetDataSemaphore(t);
        resetDataList();
        qDebug() << "[ProducerModel]清空生产者对象:" << available()
                 << m_listData.count();
    }

    //安全放入Data(本线程或使用者线程)
    void safeIn(__ProducerData *pData)
    {
        getDataList()->append(pData);
        comingNetDataSemaphore();
        releaseDataList();
    }

    //安全拿出Data(使用者线程)
    __ProducerData *safeOut()
    {

        /*方法1:
        QList<_GameData*> *pDataList = getDataList();
        if(pDataList->count() == 0)
        {
            releaseDataList();
            Debug(_T("等待中..."));
            //RefreshUI();
            WaitForNet();
            pDataList = getDataList();
        }
        m_mutexUserAction.tryLock();


        //方法2:
        QList<_GameData*> *pDataList;
        while(1)
        {
            pDataList = getDataList();
            if(pDataList->count() == 0)
            {
                releaseDataList();
                Debug(_T("等待中..."));
                //RefreshUI();
                WaitForNet();
                if(gameStatus() != Game_Status_Continue)
                    break;
            }
            else
                break;
        }
        if(gameStatus() != Game_Status_Continue)
            return nullptr;
        */


        /*方法3:
        QList<__ProducerData*> *pListData;

        pListData = getDataList();
        qDebug() << "等待中1...";
        while(!m_semaphoreData.tryAcquire())
        {
            releaseDataList();
            qDebug() << "等待中2...";
            usingNetDataSemaphore();

            //if(gameStatus() != Game_Status_Continue)
            //    return nullptr;

            pListData = getDataList();
            qDebug() << "thread:get!";
            break;
            //RefreshUI();
            //WaitForNet();
            //if(gameStatus() != Game_Status_Continue)
            //    break;
        }*/



        //!!!方法4:
        QList<__ProducerData*> *pListData = nullptr;

        qDebug() << "等待中1...";
        usingNetDataSemaphore();
        qDebug() << "等待中2...";
        pListData = getDataList();
        qDebug() << "thread:get!";



        /*
        //qDebug() << "m_mutexData.tryLock():" << m_mutexData.tryLock() << ::GetCurrentThreadId() << QThread::currentThreadId();;

        qDebug() << "游戏队列中有数据:" << pListData->count();
        QList<_GameData*>::iterator ii;
        for(ii = pListData->begin(); ii != pListData->end(); ii++)
        {
            qDebug() << "数据:" << (*ii)->type;
        }*/

        __ProducerData *pData = nullptr;
        if(!pListData->isEmpty())
            pData = pListData->takeFirst();

        releaseDataList();

        return pData;
    }

    //通知semaphore入或出
    void comingNetDataSemaphore(int n = 1)
    {
        m_semaphoreData.release(n);
        qDebug() << "增加一个Semaphore";
    }
    void usingNetDataSemaphore(int n = 1)
    {
        m_semaphoreData.acquire(n);
        qDebug() << "减少一个Semaphore";
    }

    int available()
    {
        return m_semaphoreData.available();
    }

protected:
    QQueue<__ProducerData*> m_listData; //游戏数据(传输)
    mutable QMutex m_mutexData;
    QSemaphore m_semaphoreData;


    //锁住并返回
    QList<__ProducerData*> *getDataList()
    {
        //Debug_Leamus(QString("m_mutexData.lock()"));
        qDebug()<<"m_mutexData lock0!!!";
        m_mutexData.lock();
        qDebug()<<"m_mutexData lock1!!!";
        return &m_listData;
    }

    //释放datalist
    void releaseDataList()
    {
        qDebug()<<"m_mutexData trylock unlock0!!!";
        //Debug_Leamus("m_mutexData.unlock()");
        //m_mutexData.tryLock();
        m_mutexData.unlock();
        qDebug()<<"m_mutexData trylock unlock1!!!";
    }

    //清除DataList(本线程或使用者线程)
    void resetDataList()
    {
        getDataList();
        /*while(!list->isEmpty())
            delete list->takeFirst();*/
        qDeleteAll(m_listData);
        m_listData.clear();

        releaseDataList();
    }

    /*
    #include <QEventLoop>

    _GameData* Game::WaitingForOthers()
    {
        QEventLoop eventLoop;
        eventLoop.exec();
    }
    */

};



////////////////////池类///////////////////

template< class _TData >
class _LMS_Pool
{
public:
    class _Data: public _TData
    {
    //函数
    public:
        explicit _Data()//:m_Position(nullptr)
        //    ,pExtraData(nullptr)
        {
            m_bInit = false;
            m_bRelease = true;
            //_init();
        }
        virtual ~_Data()
        {
            _release();
            //m_bInit = false;
            //m_bRelease = true;
        }

        //每次 调出 时的初始化或 调入时的 释放
        virtual void _init()
        {
            if(!m_bInit)
            {
                m_bInit = true;
                m_bRelease = false;
                //pos = nullptr;
                _TData::_pool_init();
            }
        }
        virtual void _release()
        {
            if(!m_bRelease)
            {
                m_bInit = false;
                m_bRelease = true;
                //pos = nullptr;
                _TData::_pool_release();
            }
        }

    public:
        //POSITION m_Position;    //在列表中的位置
        //void *pExtraData;

        //保证初始化一次和释放一次
        bool m_bInit;
        bool m_bRelease;
    };

public:
    explicit _LMS_Pool()
    {
        /*
        if((m_hMutexListUsing = ::CreateMutex(nullptr, FALSE, "")) == nullptr)
        {
            TRACE(_T("[IOCPDEBUG]创建MutexUsing失败，错误代码: %d!"), WSAGetLastError());
        }
        if((m_hMutexListEmpty = ::CreateMutex(nullptr, FALSE, "")) == nullptr)
        {
            TRACE(_T("[IOCPDEBUG]创建MutexEmpty失败，错误代码: %d!"), WSAGetLastError());
        }

        InitializeCriticalSection(&m_csListUsing);
        InitializeCriticalSection(&m_csListEmpty);
        */

        m_nReserveCount = 0;

        return;
    }
    virtual ~_LMS_Pool()
    {
        clearEmptyList();
        clearUsingList();

        //RELEASE_HANDLE(m_hMutexListUsing);
        //RELEASE_HANDLE(m_hMutexListEmpty);
    }

//其他函数
public:
    //得到一个空的Data,并加入到Using中,返回此Data
    //会查找EmptyList,如果没有则新建
    _TData* getOneEmpty()
    {
        m_mutexListEmpty.lock();
        //WaitForSingleObject(m_hMutexListEmpty, INFINITE);
        _Data* d = nullptr;

        //补足最低数
        while(m_listEmpty.length() < m_nReserveCount + 1)
        {
            d = new _Data;
            if(nullptr != d)
                m_listEmpty.append(d);
            else
                qWarning("getOneEmpty Warning:new _Data is nullptr");
        }

        if(m_listEmpty.length() == 0)
        {
            m_mutexListEmpty.unlock();
            //ReleaseMutex(m_hMutexListEmpty);
            d = new _Data;
            if(d == nullptr)
            {
                qWarning("getOneEmpty Error:new _Data is nullptr");
                return nullptr;
            }
        }
        else
        {
            d = m_listEmpty.takeFirst();
            m_mutexListEmpty.unlock();
            //ReleaseMutex(m_hMutexListEmpty);
        }

        d->_pool_init();

        m_mutexListUsing.lock();
        //WaitForSingleObject(m_hMutexListUsing, INFINITE);
        //d->pos =
        m_listUsing.append(d);
        m_mutexListUsing.unlock();
        //ReleaseMutex(m_hMutexListUsing);
        return d;
    }

    //释放一个UsingData,并加入到EmptyList中
    //返回UsingData剩余个数
    //错误返回-1
    int releaseOneUsing(_TData *td)
    {
        if(td == nullptr)
        {
            qCritical("releaseOneUsing Err:nullptr");
            return -1;
        }

        _Data* d = (_Data*)td;
        int n;
        m_mutexListUsing.lock();
        //WaitForSingleObject(m_hMutexListUsing, INFINITE);
        m_listUsing.removeOne(d);
        n = m_listUsing.length();
        m_mutexListUsing.unlock();
        //ReleaseMutex(m_hMutexListUsing);
        //if(d==nullptr)return -1;

        d->_pool_release();
        //d->pExtraData = nullptr;

        m_mutexListEmpty.lock();
        //WaitForSingleObject(m_hMutexListEmpty, INFINITE);

        m_listEmpty.append(d);
        m_mutexListEmpty.unlock();
        //ReleaseMutex(m_hMutexListEmpty);
        return n;
    }
/*
    //释放一个列表到EmptyList,其他同上
    int releaseListUsing(QList<_TData*> &tlist)
    {
        POSITION pos;
        pos = tlist.GetHeadPosition();
        EnterCriticalSection(&m_csListUsing);
        //WaitForSingleObject(m_hMutexListUsing, INFINITE);
        while(pos != nullptr)
        {
            m_listUsing.RemoveAt(((_Data*)tlist.GetNext(pos))->pos);
        }
        int n = m_listUsing.GetCount();
        LeaveCriticalSection(&m_csListUsing);
        //ReleaseMutex(m_hMutexListUsing);


        pos = tlist.GetHeadPosition();
        EnterCriticalSection(&m_csListEmpty);
        //WaitForSingleObject(m_hMutexListEmpty, INFINITE);
        while(pos != nullptr)
        {
            _Data* d = (_Data*)tlist.GetNext(pos);
            d->_release();
            //d->pExtraData = nullptr;
            m_listEmpty.AddTail(d);
        }

        LeaveCriticalSection(&m_csListEmpty);
        //ReleaseMutex(m_hMutexListEmpty);
        return n;


        / *
        int n = 0;
        POSITION pos = tlist.GetHeadPosition();

        while(pos != nullptr)
        {
            releaseOneUsing(tlist.GetNext(pos));
            n++;
        }
        return n;
        * /
    }*/

    //清空EmptyList
    void clearEmptyList()
    {
        m_mutexListEmpty.lock();
        //WaitForSingleObject(m_hMutexListEmpty, INFINITE);

        qDeleteAll(m_listEmpty);
        m_listEmpty.clear();

        m_mutexListEmpty.unlock();
        //ReleaseMutex(m_hMutexListEmpty);
    }

    //清空UsingList
    void clearUsingList()
    {
        m_mutexListUsing.lock();
        //WaitForSingleObject(m_hMutexListUsing, INFINITE);

        qDeleteAll(m_listUsing);
        m_listUsing.clear();

        m_mutexListUsing.unlock();
        //ReleaseMutex(m_hMutexListUsing);
    }

public:
    QList<_Data*> m_listUsing;
    QList<_Data*> m_listEmpty;

    //HANDLE m_hMutexListUsing;
    //HANDLE m_hMutexListEmpty;
    QMutex  m_mutexListUsing;
    QMutex  m_mutexListEmpty;

    int     m_nReserveCount;    //最少预留多少个

};





#endif // GLOBAL_H
